package com.eliza.library.utils.net

import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.serialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.decodeStructure
import kotlinx.serialization.encoding.encodeStructure
import kotlinx.serialization.serializer

@Serializable
sealed class OptionResult<out R> {
    data class Success<T>(val data: T) : OptionResult<T>()
    data class Error(val exception: Exception) : OptionResult<Nothing>()
}

// 可为空
@Serializable
data class RespResult<T>(val code: Int, val message: String, val data: T?)

@Serializable
data class PageResp<T>(val total: Int, val items: List<T>)

@Serializable
data class PageInfo(
    @SerialName("page") val current: Int,
    @SerialName("pageSize") val size: Int
)

@Serializable
data class SearchWithData<T : SerializationStrategy<T>>(val pageInfo: PageInfo, val data: T)

@Serializable
data class RequestID(val id: Long, var ids: List<Long> = emptyList<Long>())

@Serializable(with = PacketSerializer::class)
data class Anyx(val dataType: String, val payload: Any)

object PacketSerializer : KSerializer<Anyx> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Packet") {
        element("dataType", serialDescriptor<String>())
        element("payload", buildClassSerialDescriptor("Any"))
    }

    @Suppress("UNCHECKED_CAST")
    private val dataTypeSerializers: Map<String, KSerializer<Any>> =
        mapOf(
            "String" to serializer<String>(),
            "Int" to serializer<Int>(),
            //list them all
        ).mapValues { (_, v) -> v as KSerializer<Any> }

    private fun getPayloadSerializer(dataType: String): KSerializer<Any> =
        dataTypeSerializers[dataType]
            ?: throw SerializationException("Serializer for class $dataType is not registered in PacketSerializer")

    override fun serialize(encoder: Encoder, value: Anyx) {
        encoder.encodeStructure(descriptor) {
            encodeStringElement(descriptor, 0, value.dataType)
            encodeSerializableElement(
                descriptor,
                1,
                getPayloadSerializer(value.dataType),
                value.payload
            )
        }
    }

    override fun deserialize(decoder: Decoder): Anyx = decoder.decodeStructure(descriptor) {
        if (decodeSequentially()) {
            val dataType = decodeStringElement(descriptor, 0)
            val payload = decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
            Anyx(dataType, payload)
        } else {
            require(decodeElementIndex(descriptor) == 0) { "dataType field should precede payload field" }
            val dataType = decodeStringElement(descriptor, 0)
            val payload = when (val index = decodeElementIndex(descriptor)) {
                1 -> decodeSerializableElement(descriptor, 1, getPayloadSerializer(dataType))
                CompositeDecoder.DECODE_DONE -> throw SerializationException("payload field is missing")
                else -> error("Unexpected index: $index")
            }
            Anyx(dataType, payload)
        }
    }
}